﻿using System;
using System.Activities;
using System.Activities.XamlIntegration;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Zeus.Comunicaciones.Componentes.AccesoDatos;
using Zeus.Comunicaciones.Componentes.Excepciones;
using Zeus.Comunicaciones.Entidades;

namespace Zeus.Comunicaciones.Componentes
{
    public class Procesos
    {
        public bool ValidarToken { get; set; }

        protected ServiceResponse<T> InvocarGenerico<T>() where T : class
        {
            if (ValidarToken)
            {
                string token = HttpContext.Current.Request.Headers["ZeusToken"];

                Autenticacion autenticacion = new Autenticacion();

                try
                {
                    autenticacion.ValidarToken(token);
                }
                catch (Exception ex)
                {
                    return ServiceResponse<T>.From(ex);
                }
            }

            ServiceResponse<T> response = new ServiceResponse<T>
            {
                CodeMessage = -1,
                Success = true
            };

            return response;
        }

        public T Invocar<T>() where T : class
        {
            T response;

            //Type parametroGenerico = typeof(T).BaseType.GetGenericArguments()[0];

            if (typeof(T) == typeof(ServiceResponseCollection))
            {
                response = InvocarGenerico<List<CompositeEntity>>().Convert<T>();
            }
            else if (typeof(T) == typeof(ServiceResponseSingleEntity))
            {
                response = InvocarGenerico<CompositeEntity>().Convert<T>();
            }
            else
            {
                response = InvocarGenerico<object>().Convert<T>();
            }

            return response;
        }

        public T InvocarAccion<T>(Peticion peticion) where T : class
        {
            T response;

            ServiceResponseObject responseObject = InvocarAccion(peticion);

            if (typeof(T) == typeof(ServiceResponseObject))
            {
                response = (T)(object)responseObject;
            }
            else if (typeof(T) == typeof(ServiceResponseSingleEntity))
            {
                ServiceResponseSingleEntity responseSingle = new ServiceResponseSingleEntity
                {
                    CodeMessage = responseObject.CodeMessage,
                    Message = responseObject.Message,
                    Success = responseObject.Success,
                    Data = (CompositeEntity)responseObject.Data
                };

                response = (T)(object)responseSingle;
            }
            else
            {
                ServiceResponseCollection responseCollection = new ServiceResponseCollection
                {
                    CodeMessage = responseObject.CodeMessage,
                    Message = responseObject.Message,
                    Success = responseObject.Success,
                    Data = (List<CompositeEntity>)responseObject.Data
                };

                response = (T)(object)responseCollection;
            }

            return response;
        }

        protected ServiceResponseObject InvocarAccion(Peticion peticion)
        {
            ServiceResponseObject response = (ServiceResponseObject)Invocar<ServiceResponseObject>();

            try
            {
                WorkflowInvoker invoker = ObtenerWorkflowInvoker(peticion);

                Dictionary<string, object> parametros = new Dictionary<string, object>();

                if (peticion.Parametros != null)
                {
                    parametros = peticion.Parametros.ToDictionary(t => t.Key, t => t.Value);
                }

                if (peticion.EsAsincrono)
                {
                    invoker.InvokeAsync(parametros);
                }
                else
                {
                    IDictionary<string, object> respuestaWorkflow = invoker.Invoke(parametros);

                    if (respuestaWorkflow.Count > 0)
                    {
                        response.Data = respuestaWorkflow.First().Value;
                    }
                }
            }
            catch (Exception ex)
            {
                response = ServiceResponseObject.From(ex).Convert<ServiceResponseObject>();
            }

            return response;
        }

        public ServiceResponseSingleEntity Autenticacion(string usuario, string contrasena)
        {
            try
            {
                IAutenticacion autenticacion = new Autenticacion();

                string token = autenticacion.Autenticar(usuario, contrasena);

                ServiceResponseSingleEntity response = new ServiceResponseSingleEntity
                {
                    Data = CompositeEntity.From(token, "token"),
                    Success = true
                };

                return response;
            }
            catch (Exception ex)
            {
                return ServiceResponseSingleEntity.From(ex) as ServiceResponseSingleEntity;
            }
        }

        private WorkflowInvoker ObtenerWorkflowInvoker(Peticion peticion)
        {
            ZeusServiciosEntities accesoDatos = new ZeusServiciosEntities();

            WorkflowInformacion workflow = accesoDatos.WorkflowInformacion.ToList().SingleOrDefault(t => t.Nombre.Equals(peticion.NombreAccion, StringComparison.InvariantCultureIgnoreCase));

            if (workflow == default(WorkflowInformacion))
            {
                throw new InvalidWorkflowName();
            }

            TextReader reader = new StringReader(workflow.Xaml);

            Activity workflowGenerico = ActivityXamlServices.Load(reader);

            WorkflowInvoker invoker = new WorkflowInvoker(workflowGenerico);

            return invoker;
        }
    }
}
